package math;

import static math.ExpressionBuilder.mult;
import static math.ExpressionBuilder.add;

public class Mult implements ArithmeticExpression {

  private ArithmeticExpression factor1;

  private ArithmeticExpression factor2;

  private Mult(ArithmeticExpression factor1, ArithmeticExpression factor2) {
    this.factor1 = factor1;
    this.factor2 = factor2;
  }

  public static ArithmeticExpression createMult(ArithmeticExpression factor1,
      ArithmeticExpression factor2) {
    return new Mult(factor1, factor2);
  }

  @Override
  public ArithmeticExpression derivate(Variable var) {
    return add(mult(factor1.derivate(var), factor2), mult(factor1, factor2.derivate(var)));
  }

  @Override
  public int getPriority() {
    return 4;
  }

  @Override
  public boolean isOne() {
    return factor1.isOne() && factor2.isOne();
  }

  @Override
  public boolean isZero() {
    return factor1.isZero() || factor2.isZero();
  }

  @Override
  public ArithmeticExpression simplify() {
    return this;
  }

  @Override
  public int countMembers() {
    return 1 + factor1.countMembers() + factor2.countMembers();
  }

  @Override
  public int hashCode() {
    return (factor1.hashCode() ^ 12342323) * (factor2.hashCode() ^ 94835);
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    if (factor1.getPriority() > getPriority())
      sb.append('(');
    sb.append(factor1.toString());
    if (factor1.getPriority() > getPriority())
      sb.append(')');
    sb.append("*");
    if (factor2.getPriority() > getPriority())
      sb.append('(');
    sb.append(factor2.toString());
    if (factor2.getPriority() > getPriority())
      sb.append(')');
    return sb.toString();
  }

  public ArithmeticExpression getFactor1() {
    return factor1;
  }
  
  public ArithmeticExpression getFactor2() {
    return factor2;
  }
  
  @Override
  public boolean matches(Expression expr) {
    if (expr instanceof Mult) {
      Mult eMult = (Mult) expr;
      return factor1.matches(eMult.getFactor1()) && factor2.matches(eMult.getFactor2());
    } else
      return false;
  }

  @Override
  public boolean equals(Object obj) {
    if (obj instanceof Mult) {
      Mult mult2 = (Mult) obj;
      return mult2.factor1.equals(factor1) && mult2.factor2.equals(factor2);
    } else
      return false;
  }

  @Override
  public <R> R accept(ExpressionVisitor<R> visitor) {
    return visitor.visitMult(this);
  }
}